﻿using Microsoft.Xaml.Behaviors.Layout;
using S7.Net;
using System;
using System.Collections;
using System.Threading.Tasks;
using System.Xml.Linq;
using WFStandard.WFThread;
using Def = CommonLibrary.WFFile.SysDef;
namespace DemountCIM.Framework.PLC
{
    public class S7Plc
    {
        #region // 读取步骤

        protected enum ReadSteps
        {
            Read_Start = 0,
            Read_IOState,
            Read_IntData,
            Read_Finished,
            Read_End,
        }

        #endregion


        #region // 字段

        public string IP { get; private set; }          // PLC IP地址
        public int Port { get; private set; }           // PLC 端口号
        public int Rack { get; private set; }           // PLC 机架号
        public int Slot { get; private set; }           // PLC 槽位号

        private object nextStep;                        // 读取步骤
        private Plc plcClient;                          // PLC客户端
        private PlcData plcData;                        // PLC数据
        private PlcData plcDataBuf;                     // PLC数据缓存
        private BaseThreadEx threadRead;                // 数据读取线程
        private Object plcLock;                         // PLC资源锁

        #endregion


        #region // 构造函数

        public S7Plc(string ip = "127.0.0.1", int port = 502, int rack = 0, int slot = 0)
        {
            IP = ip;
            Port = port;
            Rack = rack;
            Slot = slot;
            nextStep = 0;
            plcData = new PlcData();
            plcDataBuf = new PlcData();
            plcLock = new object();
            threadRead = new BaseThreadEx(ReadData);
            plcClient = new Plc(CpuType.S71500, ip, port, (short)rack, (short)slot);
            plcClient.ReadTimeout = 3000; // 超时
            plcClient.WriteTimeout = 3000; // 超时
        }

        #endregion


        #region // 私有方法

        /// <summary>
        /// 数据读取线程
        /// </summary>
        private void ReadData()
        {
            try
            {
                if (!IsConnected())
                {
                    Thread.Sleep(300);
                    return;
                }

                switch ((ReadSteps)this.nextStep)
                {
                    case ReadSteps.Read_Start:
                        {
                            this.nextStep = ReadSteps.Read_IOState;
                            break;
                        }
                    case ReadSteps.Read_IOState:
                        {
                            lock (plcLock)
                            {

                                BitArray bitArray = (BitArray)plcClient.Read(DataType.DataBlock, 800, 0, VarType.Bit, 65);

                                plcDataBuf.demounter2Station[0] = bitArray[0];
                                plcDataBuf.demounter2Station[1] = bitArray[1];
                                plcDataBuf.demounter2Station[2] = bitArray[3];

                                plcDataBuf.demounter1Station[0] = bitArray[6];
                                plcDataBuf.demounter1Station[1] = bitArray[7];
                                plcDataBuf.demounter1Station[2] = bitArray[9];


                                plcDataBuf.palletizingStation[0] = bitArray[12];
                                plcDataBuf.palletizingStation[1] = bitArray[13];
                                plcDataBuf.palletizingStation[2] = bitArray[15];

                                plcDataBuf.removeGlueStation[0] = bitArray[18];
                                plcDataBuf.removeGlueStation[1] = bitArray[19];

                                plcDataBuf.cleaningStation[0] = bitArray[22];
                                plcDataBuf.cleaningStation[1] = bitArray[23];
                                plcDataBuf.cleaningStation[2] = bitArray[24];


                                plcDataBuf.plateCartLoadASK[1] = bitArray[38];
                                plcDataBuf.plateCartLoadASK[0] = bitArray[39];


                                plcDataBuf.plateCartUnloadASK[1] = bitArray[40];
                                plcDataBuf.plateCartUnloadASK[0] = bitArray[41];


                                plcDataBuf.plateAMRArrived[1] = bitArray[42];
                                plcDataBuf.plateAMRArrived[0] = bitArray[43];


                                plcDataBuf.plateCartArrived[1] = bitArray[44];
                                plcDataBuf.plateCartArrived[0] = bitArray[45];


                                plcDataBuf.beamCartLoadASK = bitArray[49];
                                plcDataBuf.beamCartUnloadASK = bitArray[50];
                                plcDataBuf.beamCartArrived = bitArray[51];
                                plcDataBuf.beamAMRArrived = bitArray[52];

                                this.nextStep = ReadSteps.Read_IntData;
                            }

                            break;
                        }
                    case ReadSteps.Read_IntData:
                        {
                            lock (plcLock)
                            {
                                short[] intData = (short[])plcClient.Read(DataType.DataBlock, 800, 10, VarType.Int, 14);

                                plcDataBuf.equipmentState = intData[0];
                                plcDataBuf.equipmentSubState = intData[2];
                                plcDataBuf.curPortAccessMode[0] = intData[4];
                                plcDataBuf.curPortAccessMode[1] = intData[5];
                                plcDataBuf.curPortAccessMode[2] = intData[6];

                                plcDataBuf.demounter1State = intData[9];
                                plcDataBuf.demounter2State = intData[10];
                                plcDataBuf.palletizingState = intData[11];
                                plcDataBuf.removeGlueState = intData[12];
                                plcDataBuf.cleaningState = intData[13];


                                this.nextStep = ReadSteps.Read_Finished;
                            }

                            break;
                        }
                    case ReadSteps.Read_Finished:
                        {
                            plcData.CopyFrom(plcDataBuf);
                            this.nextStep = ReadSteps.Read_Start;
                            break;
                        }
                }
            }
            catch (PlcException ex)
            {
                string strInfo = string.Format("({0:D4}){1}", (int)ex.ErrorCode, ex.Message);
                Console.WriteLine(strInfo);
            }

            Thread.Sleep(100);
        }

        #endregion


        #region // 对外接口

        /// <summary>
        /// 连接PLC
        /// </summary>
        /// <param name="strErrInfo"></param>
        /// <returns></returns>
        public bool Connect(ref string strErrInfo)
        {
            try
            {
                if (!IsConnected())
                {
                    plcClient.Open();
                    threadRead.InitThread(string.Format("PLC客户端读取任务（{0}:{1}）", IP, Port));
                }
                return true;
            }
            catch (PlcException ex)
            {
                string strInfo = string.Format("({0:D4}){1}", (int)ex.ErrorCode, ex.Message);
                if (null != strErrInfo) strErrInfo = strInfo;
                Console.WriteLine(strInfo);
                return false;
            }
        }

        /// <summary>
        /// 断开连接
        /// </summary>
        /// <param name="strErrInfo"></param>
        /// <returns></returns>
        public bool Disconnect(ref string strErrInfo)
        {
            try
            {
                plcClient.Close();
                threadRead.ReleaseThread();
                return true;
            }
            catch (PlcException ex)
            {
                string strInfo = string.Format("({0:D4}){1}", (int)ex.ErrorCode, ex.Message);
                if (null != strErrInfo) strErrInfo = strInfo;
                Console.WriteLine(strInfo);
                return false;
            }
        }

        /// <summary>
        /// 连接状态
        /// </summary>
        /// <returns></returns>
        public bool IsConnected()
        {
            return plcClient.IsConnected;
        }


        /// <summary>
        /// RFID读取成功
        /// </summary>
        /// <param name="msg"></param>
        /// <returns></returns>
        public bool ReadFinishRFID1(bool flag, ref string msg)
        {
            if (Def.IsNoHardware())
                return true;
            try
            {
                lock (plcLock)
                {
                    string strAddr = "DB800.DBX1.0";
                    plcClient.Write(strAddr, flag);

                    return true;
                }
            }
            catch (PlcException ex)
            {
                string strInfo = string.Format("({0:D4}){1}", (int)ex.ErrorCode, ex.Message);
                msg = strInfo;
                Console.WriteLine(strInfo);
                return false;
            }
        }

        /// <summary>
        /// RFID读取成功
        /// </summary>
        /// <param name="msg"></param>
        /// <returns></returns>
        public bool ReadFinishRFID2(bool flag, ref string msg)
        {
            if (Def.IsNoHardware())
                return true;
            try
            {
                lock (plcLock)
                {
                    string strAddr = "DB800.DBX0.2";
                    plcClient.Write(strAddr, flag);

                    return true;
                }
            }
            catch (PlcException ex)
            {
                string strInfo = string.Format("({0:D4}){1}", (int)ex.ErrorCode, ex.Message);
                msg = strInfo;
                Console.WriteLine(strInfo);
                return false;
            }
        }

        /// <summary>
        /// RFID读取成功
        /// </summary>
        /// <param name="msg"></param>
        /// <returns></returns>
        public bool ReadFinishRFID3(bool flag, ref string msg)
        {
            if (Def.IsNoHardware())
                return true;
            try
            {
                lock (plcLock)
                {
                    string strAddr = "DB800.DBX1.6";
                    plcClient.Write(strAddr, flag);

                    return true;
                }
            }
            catch (PlcException ex)
            {
                string strInfo = string.Format("({0:D4}){1}", (int)ex.ErrorCode, ex.Message);
                msg = strInfo;
                Console.WriteLine(strInfo);
                return false;
            }
        }

        /// <summary>
        /// RFID读取成功
        /// </summary>
        /// <param name="msg"></param>
        /// <returns></returns>
        public bool ReadFinishRFID4(bool flag, ref string msg)
        {
            if (Def.IsNoHardware())
                return true;
            try
            {
                lock (plcLock)
                {
                    string strAddr = "DB800.DBX3.1";
                    plcClient.Write(strAddr, flag);

                    return true;
                }
            }
            catch (PlcException ex)
            {
                string strInfo = string.Format("({0:D4}){1}", (int)ex.ErrorCode, ex.Message);
                msg = strInfo;
                Console.WriteLine(strInfo);
                return false;
            }
        }


        /// <summary>
        /// 外部提取PLC数据
        /// </summary>
        /// <returns></returns>
        public bool ReadPlcData(ref PlcData pData)
        {
            if (null != pData)
            {
                pData.CopyFrom(plcData);
                return true;
            }
            return false;
        }

        #endregion
    }
}
